#ifndef __WFW_LOGWRITER_CPP
#define __WFW_LOGWRITER_CPP

#include "LogWriter.h"

//***** 优先级定义 *****
const char* s_priorityStr[] =
{
	"FATAL",	// 0
	"WARNING",	// 1
	"IMPORTANT",// 2
	"INFO",		// 3
	"DETAIL",	// 4
	"DEBUG",	// 5
	"?????",	// 6: 未定义的优先等级
};

/**********************************************************************************
* static member
**********************************************************************************/
WFW_LogWriter* WFW_LogWriter::m_mainLogWriter = NULL;

/**********************************************************************************
* 函数名：constructor
* 功能  ：构造函数
**********************************************************************************/
WFW_LogWriter::WFW_LogWriter()
	:buffer(NULL),
	bufSize(MAX_FILE_SIZE),
	writePos(0),
	readPos(0),
	m_fd(-1),
	isFull(false),
	isStopped(false),
	m_readerThread(0xFFFFFFFF),
	m_outPutPriority(6)
{
	buffer = new char[bufSize];
	memset(buffer, 0x00, bufSize);
	pthread_mutex_init(&mutex, NULL);
}

/**********************************************************************************
* 函数名：deconstructor
* 功能  ：析构函数
**********************************************************************************/
WFW_LogWriter::~WFW_LogWriter()
{
	if(NULL != buffer)
	{
		delete[] buffer;
	}
}

/**********************************************************************************
* 函数名：getMainLog
* 功能  ：返回类实例
* 参数  ：无
* 返回值：类实例的指针
**********************************************************************************/
WFW_LogWriter* WFW_LogWriter::getMainLog()
{
	if(NULL == m_mainLogWriter)
	{
		m_mainLogWriter = new WFW_LogWriter();
	}
	
	return m_mainLogWriter;
}
	
/**********************************************************************************
* 函数名：write
* 功能  ：将指定buf的内容依序写入buffer
* 参数  ：buf -> 将要写入的内容
*        len -> 写入内容的长度
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::write(char* buf, int len)
{
	int emptySize, writeSize = 0;
	int index;
	
	if(len > bufSize)
	{
		//★★★写入的内容太长★★★
		buf = "Message too long to write log";
		len = strlen(buf);
	}
	
	pthread_mutex_lock(&mutex);
	if((writePos == readPos) && isFull)
	{
		//buffer当前已经写满
		pthread_mutex_unlock(&mutex);
		for(index = (WFW_LogWriter::MAX_WAIT_TIME_WHEN_BUF_FULL/WFW_LogWriter::WAIT_INTERVAL_WHEN_BUF_FULL); index > 0 ; index --)
		{
			//★★★稍作等待★★★
			usleep(WFW_LogWriter::WAIT_INTERVAL_WHEN_BUF_FULL * 1000);
			pthread_mutex_lock(&mutex);
			if(!isFull && writePos == readPos)
			{
				break;
			}
			pthread_mutex_unlock(&mutex);
		}
		
		if(index <= 0 )
		{
			//★★★←←未实现←→★★★
			//buffer始终不可写，写入syslog
			//WFW_LogWriter::syslogOutput(priority)
			return;
		}
	}
	
	emptySize = readPos - writePos;
	if(writePos >= readPos)
	{
		emptySize += bufSize;
	}
	
	if(emptySize < len)
	{
		//buffer剩余空间不足时，等待...
		pthread_mutex_unlock(&mutex);
		for(index = (WFW_LogWriter::MAX_WAIT_TIME_WHEN_BUF_FULL/WFW_LogWriter::WAIT_INTERVAL_WHEN_BUF_FULL); index > 0 ; index --)
		{
			//★★★稍作等待★★★
			usleep(WFW_LogWriter::WAIT_INTERVAL_WHEN_BUF_FULL * 1000);
			pthread_mutex_lock(&mutex);
			if(!isFull && writePos == readPos)
			{
				break;
			}
			pthread_mutex_unlock(&mutex);
		}
		
		if(index <= 0 )
		{
			//★★★←←未实现←→★★★
			//buffer的空余空间始终不够写，写入syslog
			//WFW_LogWriter::syslogOutput(priority)
			return;
		}
	}
	
	//第一回写入buffer
	if(writePos + len > bufSize)
	{
		writeSize += bufSize - writePos;
		memcpy(buffer + writePos, buf, writeSize);
		len -= writeSize;
		writePos = 0;
	}
	
	//第二回写入buffer
	memcpy(buffer + writePos, buf + writeSize, len);
	writePos += len;
	
	if(readPos == writePos)
	{
		isFull = true;
	}
	
	pthread_mutex_unlock(&mutex);
}

/**********************************************************************************
* 函数名：readerThreadMain
* 功能  ：启动buffer内容读取线程，并设定将要屏蔽的信号
* 参数  ：无
* 返回值：无
**********************************************************************************/
void* WFW_LogWriter::readerThreadMain(void* arg)
{
	/* 屏蔽指定信号 */
	sigset_t sigmask;
	sigemptyset(&sigmask);
	sigaddset(&sigmask, SIGCHLD);
	sigaddset(&sigmask, SIGALRM);
	sigaddset(&sigmask, SIGUSR1);
	
	pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
	WFW_LogWriter* my = (WFW_LogWriter*)arg;
	my->readLoop();
	
	return NULL;
}

/**********************************************************************************
* 函数名：readLoop
* 功能  ：buffer读取线程，依序从buffer中读取内容，并将读取到的内容写入到
*         当前已经打开的Log文件
* 参数  ：无
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::readLoop()
{
	off_t offset;
	
	while(!isStopped)
	{
		//★★★ 稍作等待 ★★★
		usleep(100 * 1000);
		
		pthread_mutex_lock(&mutex);
		//是否有内容可读
		if((writePos == readPos) && !isFull)
		{
			//buffer为空
			pthread_mutex_unlock(&mutex);
			continue;
		}
		
		//Log文件写满判断
		offset = lseek(m_fd, 0, SEEK_CUR);
		if(offset >= MAX_FILE_SIZE)
		{
			//文件写满
			::close(m_fd);
			m_fd = -1;
			WFW_LogWriter::rotateLog(this->m_fileName, WFW_LogWriter::MAX_FILE_NUM);
			
			m_fd = ::open(m_fileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 
				S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IWOTH|S_IROTH);
			if(m_fd < 0)
			{
				pthread_mutex_unlock(&mutex);
				::perror("文件打开失败!");
				break;
			}
		}
		
		else if(!access(m_fileName.c_str(), F_OK))
		{
			/* 文件不存在：文件由于备份、人为移动时 */
			::close(m_fd);
			m_fd = -1;
			
			m_fd = ::open(m_fileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 
				S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IWOTH|S_IROTH);
			if(m_fd < 0)
			{
				pthread_mutex_unlock(&mutex);
				::perror("文件打开失败!");
				break;
			}
		}
		
		if(readPos >= writePos)
		{
			/* 第一次读取buffer，并存档 */
			::write(m_fd, buffer + readPos, bufSize - readPos);
			readPos = 0;
		}
		
		/* 第二次读取buffer，并存档 */
		::write(m_fd, buffer + readPos, writePos - readPos);
		readPos = writePos;
		
		isFull = false;
		pthread_mutex_unlock(&mutex);
	}
}

/**********************************************************************************
* 函数名：rotateLog
* 功能  ：轮换Log文件名
* 参数  ：filePath -> 文件路径
*         maxFileNum -> 文件最大后缀数值
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::rotateLog(string filePath, int maxFileNum)
{
	string newFilePath, oldFilePath;
	string maxNumPath;
	char extF[256];
	memset(extF, 0x00, sizeof(extF));
	//根据设定的最大文件数(MaxFileNum)，得到文件末尾Format								
	//MaxFileNum < 9			文件后缀***.1
	//MaxFileNum < 99			文件后缀***.01
	//MaxFileNum < 999		文件后缀***.001

	static const char* fmt = NULL;
	if(fmt == NULL)
	{
		if(maxFileNum <= 9)
		{
			fmt = "%d";
		}
		
		else if(maxFileNum <= 99)
		{
			fmt = "%02d";
		}
		
		else if(maxFileNum <= 999)
		{
			fmt = "%03d";
		}
		
		else
		{
			fmt = "%04d";
		}
	}
	
	/* 删除最后一个文件 */
	sprintf(extF, fmt, maxFileNum);
	maxNumPath = filePath + "." + extF;
	::unlink(maxNumPath.c_str());
	
	//文件重命名
	//***.9  → 删除
	//***.8  → ***.9
	//***.7  → ***.8
	//***.6  → ***.7
	//***.5  → ***.6
	//***.4  → ***.5
	//***.3  → ***.4
	//***.2  → ***.3
	//***.1  → ***.2
	//***    → ***.1
	
	for(int index = maxFileNum ; index > 0; index --)
	{
		sprintf(extF, fmt, maxFileNum);
		newFilePath = filePath + "." + extF;
		if(index == 1)
		{
			oldFilePath = filePath;
		}
		else
		{
			sprintf(extF, fmt,maxFileNum - 1);
			oldFilePath = filePath + "." + extF;
		}
		
		::rename(oldFilePath.c_str(), newFilePath.c_str());
	}
}

/**********************************************************************************
* 函数名：syslogOutput
* 功能  ：如果写Log出现异常的话，将内容写入到syslog中
* 参数  ：priority -> 优先级
*         msg -> 内容
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::syslogOutput(int priority, string msg)
{
	
}

/**********************************************************************************
* 函数名：log
* 功能  ：重载函数，格式化Msg内容调用write函数，写入Log文件
* 参数  ：priority -> 优先级
*        format -> 内容的优先级
*        ... -> 参数
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::log(int priority, const char* format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	log(priority, format, ap);
	va_end(ap);
}

/**********************************************************************************
* 函数名：log
* 功能  ：重载函数，格式化Msg内容调用write函数，写入Log文件
* 参数  ：priority -> 优先级
*        format -> 内容的优先级
*        va_list -> 参数
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::log(int priority, const char* format, va_list args)
{
	//低于指定优先级
	if(priority > m_outPutPriority)
	{
		return;
	}
	
	/* 例：2013/07/30 20:53:40.264 [12345][34556] [INFO] args */
	char linestr[8192];
	char tmpbuf[4096];
	int pos = 0;
	
	memset(tmpbuf, 0x00, sizeof(tmpbuf));
	memset(linestr, 0x00, sizeof(linestr));
	//时间
	struct tm nowTime;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	localtime_r(&tv.tv_sec, &nowTime);
	strftime(linestr, sizeof(linestr), "%Y/%m/%d %H:%M:%S.", &nowTime);
	pos += strlen(linestr);
	
	//毫秒
	sprintf(tmpbuf, "%03d", (int)tv.tv_usec/1000);
	pos += strlen(tmpbuf);
	strcat(linestr, tmpbuf);
	
	strcat(linestr, " ");
	pos += 1;
	
	//进程ID， 线程ID情报
	sprintf(tmpbuf, "[%d][%ld]", getpid(), syscall(SYS_gettid));
	pos += strlen(tmpbuf);
	strcat(linestr, tmpbuf);
	
	//优先级情报
	if(priority < 0 || priority > 6)
	{
		// 防止数组越界
		priority = 6;
	}
	memset(tmpbuf, 0x00, sizeof(tmpbuf));
	sprintf(tmpbuf, "[%s] ", s_priorityStr[priority]);
	pos += strlen(tmpbuf);
	strcat(linestr, tmpbuf);
	
	//用户指定内容追加
	vsprintf(linestr + pos, format, args);
	linestr[strlen(linestr)] = '\n';
	write(linestr, strlen(linestr));
}

/**********************************************************************************
* 函数名：perror
* 功能  ：重写系统的perror函数，将perror内容“重定向”到Log文件
* 参数  ：priority -> 优先级
*        format -> 内容的优先级
*        ... -> 参数
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::perror(int priority, const char* format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	log(priority, format, ap);
	va_end(ap);
}

/**********************************************************************************
* 函数名：start
* 功能  ：启动buffer读取
* 参数  ：无
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::start(const string& fileFullName)
{
	this->m_fileName = fileFullName;
	m_fd = ::open(m_fileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 
				S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IWOTH|S_IROTH);
	if(m_fd < 0)
	{
		::perror("文件打开失败!");
		return;
	}
	
	m_status = stInitial;
	pthread_create(&m_readerThread, NULL, &readerThreadMain, this);
}

/**********************************************************************************
* 函数名：stop
* 功能  ：停止整个Log写入功能
* 参数  ：无
* 返回值：无
**********************************************************************************/
void WFW_LogWriter::stop()
{
	if(0xFFFFFFFF != this->m_readerThread)
	{
		pthread_join(m_readerThread, NULL);
	}
}

#endif
